package com.xframe.common.core.service.command;

import com.alibaba.fastjson2.JSON;
import com.xframe.domain.BaseModel;
import com.xframe.domain.CredentialsContainer;
import com.xframe.domain.ModelRepositoryFactory;
import com.xframe.domain.repository.SysBaseRepository;
import com.xframe.domain.role.IUserCredentials;
import com.xframe.domain.sys.SysModel;
import com.xframe.common.core.aop.XAOPContext;
import com.xframe.common.core.aop.XAOPRuntime;
import com.xframe.common.core.constant.ErrorConstant;
import com.xframe.domain.CommandModel;
import com.xframe.common.core.dto.ErrorCode;
import com.xframe.common.core.dto.ModelRepositoryDTO;
import com.xframe.common.core.exception.BusinessException;
import com.xframe.common.core.service.IProcCommandService;
import com.xframe.xdal.core.domain.XDynamicModel;
import com.xframe.xdal.core.model.IModel;
import com.xframe.xdal.core.serialize.JsonConfig;
import com.xframe.xdal.core.serialize.JsonConfigContainer;
import com.xframe.xdal.core.util.StringUtil;
import com.xframe.xdal.core.util.XReflect;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
 * 功能描述:命令的基础类
 *
 * @author xufeng
 * @version 1.0
 * 2022-09-26
 */
public abstract class BaseCommand implements IProcCommandService {


    /**
     * 辅助方法构造SysModel对象
     * 构造IModel 对象
     * 构造 SysBaseRepository 对象
     *
     * @param requestArgs 命令输入对象
     * @param userCredentials 用户凭证
     * @param
     * @return ModelRepositoryDTO 打包的对象
     */
    protected ModelRepositoryDTO procRepository(CommandModel requestArgs, IUserCredentials userCredentials){
        SysModel sysModel = SysModel.getInstance(requestArgs.getModelCode());
        if (sysModel == null) {
            throw new BusinessException(ErrorCode.DB_RECORD_NOFIND,
                    StringUtil.format(ErrorConstant.DB_RECORD_NOFIND_MSG, requestArgs.getModelCode()));
        }
        IModel model = deserialization(sysModel,requestArgs);
        if(StringUtil.isEmpty(requestArgs.getModelCode())){
            throw new BusinessException(ErrorCode.MODELID_NULL, ErrorConstant.MODELID_NULL_MSG);
        }
        SysBaseRepository repository = ModelRepositoryFactory.builder(sysModel);
        repository.setBaseAttrVal(model, userCredentials);
        return new ModelRepositoryDTO().setModel(model).setRepository(repository).setSysModel(sysModel);
    }
    /**
     * 反序列化
     *
     * @param sysModel 表结构
     * @param requestArgs 前端传递的参数
     * @param
     * @return IModel 模型对象
     */
    protected IModel deserialization(SysModel sysModel,CommandModel requestArgs) throws BusinessException {
        IUserCredentials credentials = CredentialsContainer.getCredentials();
        Map<String,Object> dto = requestArgs.getCommandBodyByMap();
        JsonConfig jsonConfig = JsonConfigContainer.getConfigContainer().getJsonConfig(credentials.getLanguage(),
                requestArgs.getVer(),sysModel.getModelCode(),requestArgs.getQueryKey());
        XDynamicModel xDynamicModel = XDynamicModel.createWithConfig(sysModel,dto,jsonConfig);

        if(xDynamicModel == null){
            throw new BusinessException(ErrorCode.DESERIALIZATION_ERROR, ErrorConstant.DESERIALIZATION_ERROR_MSG);
        }
        String className = sysModel.getClassName();
        Class<BaseModel> dataType = null;
        try {
            dataType = (Class<BaseModel>) Class.forName(className);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(dataType != null && BaseModel.class.isAssignableFrom(dataType)){
            BaseModel baseModel = JSON.to(dataType,xDynamicModel);
            return baseModel;
        }
        return xDynamicModel;
    }

    /**
     * 反序列化
     *
     * @param sysModel 表结构
     * @param dto 前端传递的参数
     * @param
     * @return IModel 模型对象
     */
    protected IModel deserialization(SysModel sysModel,Map<String,Object> dto) throws BusinessException {
        IUserCredentials credentials = CredentialsContainer.getCredentials();

//        JsonConfig jsonConfig = JsonConfigContainer.getConfigContainer().getJsonConfig(credentials.getLanguage(),
//                requestArgs.getVer(),sysModel.getModelCode(),requestArgs.getQueryKey());
        XDynamicModel xDynamicModel = XDynamicModel.createWithConfig(sysModel,dto,null);

        if(xDynamicModel == null){
            throw new BusinessException(ErrorCode.DESERIALIZATION_ERROR, ErrorConstant.DESERIALIZATION_ERROR_MSG);
        }
        String className = sysModel.getClassName();
        Class<BaseModel> dataType = null;
        try {
            dataType = (Class<BaseModel>) Class.forName(className);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(dataType != null && BaseModel.class.isAssignableFrom(dataType)){
            BaseModel baseModel = JSON.to(dataType,xDynamicModel);
            return baseModel;
        }
        return xDynamicModel;
    }

    /**
     * 执行Repository上的方法
     *
     * @param dataType 数据类型
     * @param methodName 方法名称
     * @param parameterTypes 执行参数类型
     * @return Object 执行结果
     */
    protected Method getMethodByName(Class<?> dataType, String methodName,Class<?>... parameterTypes){
        Method method = XReflect.getMethodByName(dataType,methodName,parameterTypes);
        if (method == null) {
            throw new BusinessException(ErrorCode.METHOD_NOT_FIND,
                    StringUtil.format(ErrorConstant.METHOD_NOT_FIND_MSG, methodName));
        }
        return method;
    }

    protected Object execRepository(SysBaseRepository repository, String methodName,Object...parArray) throws BusinessException{
        try {
            // 反射获得方法
            Method method = XReflect.getMethodByName(repository.getClass(),methodName);
            if (method == null) {
                throw new BusinessException(ErrorCode.METHOD_NOT_FIND,
                        StringUtil.format(ErrorConstant.METHOD_NOT_FIND_MSG, methodName));
            }
            return this.execAction(repository, repository, method, parArray);
        }catch (BusinessException e){
            throw e;
        }
    }

    /**
     * 执行Repository上的方法
     *
     * @param repository 数据类型
     * @param method 方法
     * @return Object 执行结果
     */
    protected Object execRepository(SysBaseRepository repository, Method method,Object...parArray) throws BusinessException{
        try {
            // 反射获得方法
            //Method method = XReflect.getMethodByName(repository.getClass(), methodName,parArray);


            return this.execAction(repository, repository, method, parArray);
        }catch (BusinessException e){
            throw e;
        }
    }
    /**
     * 执行指定对象上的方法
     *
     * @param execObj 方法所有者的对象
     * @param repository 方法所有者对应的SysBaseRepository
     * @param method 方法对象
     * @param parArray 执行参数
     * @return Object 执行结果
     */
    protected Object execAction(Object execObj, SysBaseRepository repository,
                                Method method, Object[] parArray) throws BusinessException{

        try {
            IUserCredentials userCredentials = CredentialsContainer.getCredentials();
            XAOPRuntime runtime = XAOPRuntime.getInstance();
            XAOPContext context = new XAOPContext(execObj, repository, method, parArray, userCredentials);
            Object resaultVal = runtime.execMethod(context);
            return resaultVal;
        }catch (BusinessException e){
            throw e;
        }
    }


    /**
     * 反序列化
     *
     * @param sysModel 表结构
     * @param requestArgs 前端传递的参数
     * @param
     * @return IModel 模型对象
     */
    protected List<IModel> deserializationToList(SysModel sysModel, CommandModel requestArgs) throws BusinessException {
        IUserCredentials credentials = CredentialsContainer.getCredentials();
        ArrayList list = requestArgs.getCommandBodyByArrayList();
        JsonConfig jsonConfig = JsonConfigContainer.getConfigContainer().getJsonConfig(credentials.getLanguage(),
                requestArgs.getVer(),sysModel.getModelCode(),requestArgs.getQueryKey());
        List<IModel> modelList = new ArrayList<>();
        if(list != null && list.size() > 0) {
            for(Object obj : list) {
                Map<String, Object> map = ( Map<String, Object>)obj;
                XDynamicModel xDynamicModel = XDynamicModel.createWithConfig(sysModel, map, jsonConfig);
                if (xDynamicModel != null) {
                    modelList.add(xDynamicModel);
                }

//                String className = sysModel.getClassName();
//                Class<BaseModel> dataType = null;
//                try {
//                    dataType = (Class<BaseModel>) Class.forName(className);
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }
//                if (dataType != null && BaseModel.class.isAssignableFrom(dataType)) {
//                    BaseModel baseModel = JSON.to(dataType, xDynamicModel);
//                    list.add(baseModel);
//                }
            }
        }
        return modelList;
    }

    @Override
    public boolean needCheckToken() {
        return true;
    }
}
